\section{Интерфейс ядра для приложений}

\subsection{Ожидание}

\begin{verbatim}
int KernelWait (
        id_t id,
        int eventId,
        timeout_t timeout);
\end{verbatim}\par

Эта функция предназначена для контролируемого по времени ожидания событий или
просто паузы в работе процесса.

Если указан id ресурса, то event указывает на ресурсное событие, возникновение
которого прервет ожидание нити. Если id нулевой, то ожидание будет прервано
только по окончании временного интервала. Уничтожение отслеживаемого ресурса
интерпретируется как возникновение события, не зависимо от типа события.

Если timeout нулевой, то, не зависимо от указания идентификатора ресурса,
управление, при отсутствии конкурирующих нитей, будет отдано немедленно. При
наличии конкурирующих нитей - в порядке планирования. Время всегда задается в
микросекундах не зависимо от возможностей платформы\footnote{Не надо забывать
про магическое слово \textbf{как минимум}, б\'{о}льшие прост\'{о}и допускаются}.

Функция возвращает KERNEL\_TIMEOUT в случае указания идентификатора ресурса и
не наступлении события в обозначенный интервал времени. В противном случае
функция возвращает KERNEL\_OK.

\subsection{Поиск ресурсов}

\begin{verbatim}
int KernelFind (
        const char *name,
        size_t nameSize,
        id_t * const id);
\end{verbatim}\par

Для необходимости явно получить идентификаторы нити или процесса необходимо
использовать соответствующие ускорители. В случае указания namelen == 0, name
интерпретируется как нулезавершенная строка.

В любом случае ядро должно контролировать доступность параметров по памяти.
Кривые ссылки или неинициализированную (незамапленную) память стоит отбрасывать
на самых ранних стадиях.

% Может быть описание ускорителей перенести в другой раздел?

\subsubsection{Получение идентификатора текущей нити}

\begin{verbatim}
id_t KernelCurrentThread ();
\end{verbatim}\par

\subsubsection{Получение идентификатора текущего процесса}


\begin{verbatim}
id_t KernelCurrentProcess ();
\end{verbatim}\par

\subsection{Создание ресурсов}

\begin{verbatim}
int KernelCreate (
        int type,
        void *param,
        size_t paramSize,
        id_t * const id);
\end{verbatim}\par

Очень громоздкая функция, которая получает различные данные в зависимоти от типа
ресурса. Но в явном виде она почти не будет использоваться. Параметры создания
ресурсов можно оставить на откуп реализации.

Как уже отмечалось выше - у нас всего пять типов ресурсов. надо будет помыслить,
и возможно упростить данную функцию.

\subsubsection{Создание процесса}

\begin{verbatim}
id_t KernelCreateProcess (const void *entry);
\end{verbatim}\par

Процесс - это абстрактное понятие для системы.
Он является всего лишь объедлиняющей сущностью для выполняющихся нитей.

При создании процесса можно указать\footnote{Это можно сделать и позже, вызвав
KernelModify} точку входа в процесс.

\subsubsection{Создание нити}

\begin{verbatim}
id_t KernelCreateThread (
        const void *entry,
        const void *buffer,
        size_t bufferSize,
        int flags,
        timeout_t timeout);
\end{verbatim}\par

timeout равный нулю немедленно устанавливает нить в очередь планировщика.
timeout больше нуля дает задержку на запуск нити. Это может быть полезно для
создания ожидающих нитей.

% \subsubsection{Использование ожидающей нити для контролирования времени вызова}
%
% Необходимость контролирования времени работы может возникнуть в разных
% ситуациях. Например может возникнуть необходимость контролировать время
% обработки вызова. Хотя штатной возможности задать таймаут при вызове нету, это
% вовсе не означает что это невозможно. Нить, совершившая вызов и в старом ядре
% висела на событии, но это событие было от удаленной нити, идентификатор
% которой на клиеннте не известен. Вероятно можно будет предусмотреть какой либо
% механизм сигнализирования и в данном случае\footnote{Специальный модификатор},
% так, чтобы клиентская сторона получила управление обратно. При этом серверную
% сторону всеравно нельзя останавливать, Кроме как изменить статус соединения на
% невалидный. при длительной работе серверная сторона сможет контролировать этот
% статус и завершаться аварийно в случае необходимости.
%
% \begin{verbatim}
% int WatchDog (id_t parent, const void *buffer, size_t bufferSize, int flags)
% {
%         assert (bufferSize >= sizeof (id_t));
%         id_t worker = *(id_t *)buffer;
%
%         const int event = EVENT_BREAK;
%
%         KernelModify (worker, EVENT, &event, sizeof (int));
%         return 0;
% }
%
% ...
%         id_t worker = KernelCurrentThread ();
%         id_t watchdog = KernelCreateThread (WatchDog, &worker, sizeof (id_t), 0, 1000);
%         if (KernelCall (unthrust, req, sizeof (req), 0) == KERNEL_OK)
% ...
% \end{verbatim}\par

\subsubsection{Создание региона}

Память может быть двух типов. Обычная память, и память вводо-вывода.

\begin{verbatim}
id_t KernelCreateRegion (
        laddr_t offset,
        size_t size,
        int access,
        int flags);
\end{verbatim}\par

При создании региона обычной памяти можно использовать флаг ATTACH, для
немедленного подключения региона в адресное пространство процесcа. При этом поле
offset используется для точного позиционирования региона в памяти. В том случае,
если offset равен нулю позиция региона в памяти выбирается динамически.

Для установления жесткого физического расположения региона нужно использовать
Param\break REGION\_PHYSICALBIND.

Для установления родительского региона необходимо использовать Param
REGION\_REGIONBIND, размер создаваемого дочернего региона не должен превышать
размер родительского даже с учетом смещения в родительском регионе.

При создании региона ввода-вывода необходимо задать флаг IOMEM. Регионы
ввода-вывода так же нуждаются в подключении с использованием флага ATTACH,
или позже\footnote{При этом поле offset на большинстве систем не используется,
поскольку порты ввода вывода находятся в отдельном пространстве памяти}.

Регионы ввода-вывода нуждаются в биндинге на базовый адрес порта, что можно
проделать с помощью Param REGION\_IOBIND.

\subsubsection{Создание точки вызова}

Точки вызова - это основное средство взаимодействия приложений в системе.

\begin{verbatim}
id_t KernelCreateCallEntry (
        const void *entry,
        int maxWorkers,
        int flags);
\end{verbatim}\par

При указании maxworker == 0 - количество одновременных вызовов не ограничено.

\subsubsection{Создание пользовательского ресурса}

Для пользовательских целей в системе предусматриваются ресурсы пользовательского
типа\footnote{В дальнейшем я пока буду называть их кастомами}. Эти ресурсы
обладая всеми базовыми признаками ресурсов, как то обработка сигналов или
именование, не обозначают никаких ядерных сущностей.

С помощью Param CUSTOM\_IRQBIND можно ассоциировать кастомный ресурс с
определенным сигналом прерывания, после наступления прерывания на данный ресурс
будет послан сигнал EVENT\_CUSTOM\_IRQ.

\begin{verbatim}
id_t KernelCreateCustom ();
\end{verbatim}\par

\subsection{Вызов ресурса}

Вызывать можно только два типа ресурсов - процессы и точки вызовов. Вызов
процессов используется первый раз для создания первой нити процесса. А
последующие разы вызов может быть использован для сигнализирования процесса о
событиях в состеме. Для этого процесс должен задекларировать специальную
сигнальную точку вызова.

\begin{verbatim}
int KernelCall (
        id_t id,
        void *buffer,
        size_t buffer_size,
        int flags);
\end{verbatim}\par

Основная функция для межпроцессного взаимодействия в системе\footnote{Не стоит
воспринимать выражение KernelCall как вызов ядра. Call - это предоставляемый
ядром сервис.}.

Поле flags может содержать комбинации из следующих значений:

\begin{description}
\item[FORWARD] позволяет передать запрос по цепочке обработчиков с таким
рассчетом, чтобы ответ был доставлен непосредственно получателю.
\item[ASYNC] позволяет осуществлять вызов асинхронно. в этом случае управление
в вызвавшее приложение возвращается немедленно, а коммуникации с обработчиком
можно поддерживать только через буфер обмена.
\item[COPY] Принуждает ядро копировать блок обмена вместо перемещения его путем
маппинга. Это может потребоваться особо параноидальным приложениям.
\item[READONLY] Запрещает обработчику модифицировать буфер.
\end{description}\par

В этой функции не предусмотрен таймаут на выполнение обработчика. Потому, что
проблемы сервера в любом случае не разрешатся с введением таймаута. Убивать
нить на сервере нельзя, это может  полностью вывести сервер из строя. А не
убитая нить может работать вечно, если зациклится к примеру. Не остается другого
выхода кроме как доверять серверам.

Или можно запускать сервер через специальную прослойку, которая проконтролирует
надежность его работы, а в случае проблем - просто перезапустит сервер. Эта
прослойка (специальный сервер) в принципе может быть одна на всех.

\subsection{Подключение ресурсов}

Подключение ресурсов необходимо для использования полученных извне ресурсов,
например анонимных точек вызова. Так же это позволяет передавать ресурсы
приложения другим процессам для организации взаимодействия.

\begin{verbatim}
int KernelAttach (
        id_t resource_id,
        id_t process_id,
        int access,
        unsigned long specific);
\end{verbatim}\par

Если process == 0, то используется текущий процесс.

Specific для регионов может принимать значение линейного адреса в удаленном
процессе.

\subsection{Освобождение ресурсов}

\begin{verbatim}
int KernelDetach (
        id_t id,
        int flags);
\end{verbatim}\par

Высвобождение ресурсов вовсе не подразумевает их уничтожения. Ресурсы могут быть
использованы многочисленными процессами. И если указывается флаг DESTROY, то для
этого у процесса должны быть соответствующие права.

\subsection{Изменение ресурсов}

\begin{verbatim}
int KernelModify (
        id_t id,
        int param_id,
        void * const params,
        size_t param_size);
\end{verbatim}\par

Пока кратенько перечислю\footnote{Необходимы описания}:
% RESOURCE\_MODIFY\_DATA\footnote{Несущественная часть имени, которая может
% нести данные пользователя},
RESOURCE\_EVENT\footnote{Не помню, когда я убил ResourceEvent и куда хотел
перенаправить его функцию, склероз\ldots У меня же никогда не было такой функции,
у меня был только Wait отдельный\ldots}, CUSTOM\_IRQBIND

\subsubsection{Именование регионов}

Имя ресурса - это набор бинарных данных ограниченной длины\footnote{Где то я про
это уже писал\ldots}. Имя ресурса должно быть уникально, и может быть
использовано для поиска ресурса в системе. Но от поиска будет мало толку, если
ресурс не имеет глобальной инстанции. То есть, интересующийся процесс сможет
узнать идентификатор ресурса, но не сможет им никак воспользоваться\footnote{
Хотя в этом может быть свой смысл\ldots}.

Для изменения имени ресурса используется модификатор RESOURCE\_MODIFY\_NAME.

Если задать длину имени равной нулю, то имя ресурса будет сброшено.

\subsubsection{Биндинг регионов}

Биндинг бывает трех видов: На физическую память, на другой регион или на память
ввода-вывода. Соответственно применяются идентификаторы
RESOURCE\_MODIFY\_REGION\_PHYSICALBIND,\break RESOURCE\_MODIFY\_REGION\_REGIONBIND,
RESOURCE\_MODIFY\_REGION\_IOBIND. Но во всех случаях в качестве параметра
передается структура KernelModifyRegionBindParam.

\begin{verbatim}
struct KernelModifyRegionBindParam {
        id_t id;
        size_t size;
        paddr_t offset;
        laddr_t shift;
};
\end{verbatim}

shift задает смещение блока подключаемой памяти в регионе. Для памяти
ввода-вывода - не используется. В остальных случаях позволяет сместить блок
памяти от начала региона, при условии что размер блока позволяет вместить память
целиком. И естественно не должна нарушаться выровненность страниц.

size и shift позволяю обеспечить биндинг только части региона. Остальные
страницы выделяются в соответствии с политиками региона.

При физическом биндинге offset и size задают физический адрес и размер
подключаемой фихической памяти соответственно.

При биндинге к регионам id задает регион - источник страниц, offset и size
описывают область в пределах региона-источника.

\subsection{Информация о ресурсах}

\begin{verbatim}
int KernelInfo (
        id_t id,
        int info_id,
        void * const info,
        size * const info_size)
\end{verbatim}\par

Списки процессов и нитей по процессу выдаются в следующем формате: Первым словом
идет количество идентификаторов, далее идет список идентификаторов, но общий
объем информации не должен превышать размер буфера.
